package software.hust.com.hust_last.util;

import android.os.Handler;

import com.google.gson.Gson;
import java.io.IOException;
import java.util.Map;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import software.hust.com.hust_last.callback.IResponseCallback;
import software.hust.com.hust_last.callback.ObjectCallback;
import software.hust.com.hust_last.callback.RawCallback;

public class HttpUtil {
    private static HttpUtil sInstance = new HttpUtil();

    private OkHttpClient mClient = new OkHttpClient();

    private Handler mHandler = new Handler();

    public static HttpUtil getInstance() {
        return sInstance;
    }

    public void get(String url, Map<String, String> params, IResponseCallback callback) {
        get(null, url, params, callback);
    }

    public void get(Object tag, String url, Map<String, String> params, IResponseCallback callback) {
        StringBuilder builder = new StringBuilder();
        builder.append(url);
        if (params != null && !params.isEmpty()) {
            builder.append("?");
            for (Map.Entry<String, String> entry : params.entrySet()) {
                builder.append(entry.getKey() + "=" + entry.getValue() + "&");
            }
            builder.deleteCharAt(builder.length() - 1);
        }
        Request request = new Request.Builder()
                .url(builder.toString())
                .tag(tag)
                .build();
        mClient.newCall(request).enqueue(new InnerHandler(callback));
    }

    public void post(String url, Map<String, String> params, IResponseCallback callback) {
        post(null, url, params, callback);
    }

    public void post(Object tag, String url, Map<String, String> params, IResponseCallback callback) {
        FormBody.Builder builder = new FormBody.Builder();
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                builder.add(entry.getKey(), entry.getValue());
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .tag(tag)
                .build();
        mClient.newCall(request).enqueue(new InnerHandler(callback));
    }

    public void cancel(Object tag) {
        if (tag == null) {
            return;
        }
        for (Call call : mClient.dispatcher().queuedCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
        for (Call call : mClient.dispatcher().runningCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
    }

    public class InnerHandler implements Callback {
        IResponseCallback callback;

        public InnerHandler(IResponseCallback callback) {
            this.callback = callback;
        }

        @Override
        public void onResponse(final Call call, final Response response) throws IOException {
            if (response.isSuccessful()) {
                final String responseBody = AesUtil.decrypt(response.body().string());
                if (callback instanceof ObjectCallback) {
                    final ObjectCallback objCallback = (ObjectCallback) callback;
                    final Object obj = new Gson().fromJson(responseBody, objCallback.getType());
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            objCallback.onSuccess(response.code(), obj);
                        }
                    });
                } else if (callback instanceof RawCallback) {
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            ((RawCallback) callback).onSuccess(response.code(), responseBody);
                        }
                    });
                }
            } else {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onFailure("status message: " + response.message() +
                                " status code: " + response.code());
                    }
                });
            }
        }

        @Override
        public void onFailure(final Call call, final IOException e) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    callback.onFailure(e.toString());
                }
            });
        }
    }
}
